package com.qianfeng.nio;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

/**
 * Created by Jackiechan on 2022/7/5 14:34
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
public class NIO12Server {
    /**
     * 保存所有客户端的集合
     */
    private static List<SocketChannel> allClients = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        //搞一个selector
        Selector selector = Selector.open();
        //搞一个server channel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //绑定端口
        serverSocketChannel.bind(new InetSocketAddress("10.9.48.191", 23456));
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        //注册到selector,并且关注accept
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.err.println("服务器运行在23456端口");
        //用buffer的数组来存放数据,可以更合理的利用内存碎片
        ByteBuffer[] byteBuffers = new ByteBuffer[3];
        byteBuffers[0] = ByteBuffer.allocate(5);
        byteBuffers[1] = ByteBuffer.allocate(15);
        byteBuffers[2] = ByteBuffer.allocate(10);

        //循环
        while (true) {
            //看看有没有操作发生,没有操作就会进入等待状态,有就放行,返回的结果告诉我们有几个操作
            int select = selector.select();
            //获取到当前的所有的操作
            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            selectionKeys.forEach(selectionKey -> {
                // return;//跳出当前循环,继续下次循环
                //想要跳出整个foreach通过抛出异常来跳出
                //获取到了有操作的通道
                SelectableChannel channel = selectionKey.channel();
                //如果收到的是连接类型的操作
                if (selectionKey.isAcceptable()) {
                    try {
                        //接受连接
                        SocketChannel socketChannel = ((ServerSocketChannel) channel).accept();
                        socketChannel.configureBlocking(false);//设置为非阻塞
                        //一旦建立连接后,当前的channel就会关注消息数据
                        //设置感兴趣的操作
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        //保存当前连接到集合
                        allClients.add(socketChannel);
                        System.err.println("客户端" + socketChannel.getRemoteAddress() + "建立连接了");
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                } else if (selectionKey.isReadable()) {

                    while (true) {
                        //清理一下
                       // Arrays.stream(byteBuffers).peek(byteBuffer -> byteBuffer.clear());
                        for (ByteBuffer byteBuffer : byteBuffers) {
                            byteBuffer.clear();
                        }
                        try {
                            //读取数据,读到bytebuffer数组中
                            long read = ((SocketChannel) channel).read(byteBuffers);
                            if (read > 0) {
                                //翻转的话要挨个翻转
                                Stream.of(byteBuffers).map(byteBuffer -> byteBuffer.position() + "--->" + byteBuffer.limit()).forEach(System.err::println);
                            }else {
                                break;
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            });
            //把之前的事情清理掉
            selectionKeys.clear();
        }
    }
}
